package net.alteiar.algorithms;

import java.awt.Point;
import java.util.HashSet;
import java.util.List;
import java.util.Stack;

import net.alteiar.images.metadata.ImageInfo;

public class Utils {

	public static void fillRect(ImageInfo colors, int x, int y, int width,
			int heigth, int newColor) {
		for (int newX = x; newX < x + width; ++newX) {
			for (int newY = y; newY < y + heigth; ++newY) {
				colors.setValue(newX, newY, newColor);
			}
		}
	}

	public static void nonRecursiveFill(ImageInfo colors, Point begin,
			int oldColor, int newColor) {
		Stack<Point> pending = new Stack<Point>();
		pending.push(begin);

		HashSet<Point> visited = new HashSet<>();
		while (!pending.empty()) {
			Point p = pending.pop();
			if (!visited.contains(p)) {
				visited.add(p);

				if (isLegal(colors, p.x, p.y)
						&& colors.getValue(p.x, p.y) == oldColor) {
					colors.setValue(p.x, p.y, newColor);
					pending.push(new Point(p.x - 1, p.y));
					pending.push(new Point(p.x + 1, p.y));
					pending.push(new Point(p.x, p.y - 1));
					pending.push(new Point(p.x, p.y + 1));
				}
			}
		}
	}

	private static boolean isLegal(ImageInfo array, int i, int j) {
		if (i < 0 || j < 0)
			return false;
		if (i >= array.getWidthSquare() || j >= array.getHeightSquare())
			return false;
		return true;
	}

	public static void fill(ImageInfo info, Point org, int width, int height,
			int value, List<Point> contour) {
		boolean isInside = false;

		boolean[] moreThanOne = new boolean[width];

		for (int x = org.x; x < org.x + width; ++x) {
			int count = 0;
			for (int y = org.y; y < org.y + height; ++y) {
				if (contour.contains(new Point(x, y))
						&& !contour.contains(new Point(x, y - 1))) {
					count++;
				}
			}
			if (count > 1) {
				moreThanOne[x - org.x] = true;
			} else {
				moreThanOne[x - org.x] = false;
			}
		}

		for (int x = org.x; x < org.x + width; ++x) {
			for (int y = org.y; y < org.y + height; ++y) {
				if (moreThanOne[x - org.x]) {
					if (contour.contains(new Point(x, y))
							&& !contour.contains(new Point(x, y - 1))) {
						isInside = !isInside;
						info.setValue(x, y, value);
					} else if (isInside) {
						info.setValue(x, y, value);
					}
				}
			}
			isInside = false;
		}

		for (Point p : contour) {
			info.setValue(p.x, p.y, value);
		}
	}

	public static void fill(ImageInfo info, Point org, int width, int height,
			int value) {
		boolean isInside = false;
		for (int x = org.x; x < org.x + width; ++x) {
			for (int y = org.y; y < org.y + height; ++y) {
				if (info.getValue(x, y) == value) {
					isInside = !isInside;
				} else if (isInside) {
					info.setValue(x, y, value);
				}
			}
			isInside = false;
		}
	}
}
